#include "lpbc_test.h"
#include <stdlib.h>
#include <string.h>

info* newM_info()
{
	info* ret = (info*)malloc(sizeof(info));
	memset(ret, 0, sizeof(info));
	return ret;
}

size_t infoM_parse(info* m_p, uint8_t* in, size_t len)
{
	size_t i=0, rv=0;
	uint32_t tag;
	ProtobufCWireType wtype;
	
	check_null(m_p, 0);
	check_null(in,  0);
	if(!len)  return 0;
	for(i=0; i<len; i+=rv)
	{
		check_fail(rv+=pbc_tag(in+rv, len-rv, &tag, &wtype), 0);
		switch(tag)
		{
		case 1:		// int32 i1= 1
			check_value(wtype, PROTOBUF_C_WIRE_TYPE_VARINT, 0);
			check_fail(rv+=pbc_read_int32(in+rv, len-rv, &m_p->i1), 0);
			break;
		case 2:		// int32 i2= 2 
			check_value(wtype, PROTOBUF_C_WIRE_TYPE_VARINT, 0);
			check_fail(rv+=pbc_read_int32(in+rv, len-rv, &m_p->i2), 0);
			break;
		default: 
			return 0;
		}
	}
	return rv;
}

size_t infoM_serial(info* m_p, uint8_t* out)
{	
	byte* out_back =out;
	out += pbc_write_int32(out, PROTOBUF_C_LABEL_REQUIRED, &m_p->i1, 1);
	out += pbc_write_int32(out, PROTOBUF_C_LABEL_REQUIRED, &m_p->i2, 2);
	return out-out_back;
}

void freeM_info(info* m_p)
{
	if(m_p==NULL)
		return;
	free(m_p);
}

// test message
test* newM_test()
{
	test* ret = (test*)malloc(sizeof(test));
	memset(ret, 0, sizeof(test));
	ret->_d = newV_pbc_list(new_int32, free_value);		//
	ret->_io = newV_pbc_list(newM_info, freeM_info);
	return ret;
}

size_t testM_parse(test* m_p, uint8_t* in, size_t len)
{
	size_t i=0, rv=0;
	uint32_t tag;
	ProtobufCWireType wtype;
	
	check_null(m_p, 0);
	check_null(in,  0);
	if(!len)  return 0;
	for(i=0; i<len; i+=rv)
	{
		check_fail(rv+=pbc_tag(in+rv, len-rv, &tag, &wtype), 0);
		switch(tag)
		{
		case 1:		// int32 a= 1
			check_value(wtype, PROTOBUF_C_WIRE_TYPE_VARINT, 0);
			check_fail(rv+=pbc_read_int32(in+rv, len-rv, &m_p->_a), 0);
			break;
		case 2:		// int32 b= 2 
			check_value(wtype, PROTOBUF_C_WIRE_TYPE_VARINT, 0);
			check_fail(rv+=pbc_read_int32(in+rv, len-rv, &m_p->_b), 0);
			break;
		case 3:		// int32 c= 3
			check_value(wtype, PROTOBUF_C_WIRE_TYPE_VARINT, 0);
			check_fail(rv+=pbc_read_int32(in+rv, len-rv, &m_p->_c), 0);
			break;
		case 4:		// repeated int32 d = 4
			check_value(wtype, PROTOBUF_C_WIRE_TYPE_VARINT, 0);
			check_fail(rv+=pbc_read_int32(in+rv, len-rv, testM_d_add(m_p)), 0);
			break;
		case 5:		// info io = 5
			{
				uint32_t lens=0;
				check_value(wtype, PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED, 0);
				check_fail(rv+=pbc_read_message(in+rv, len-rv, (void*)testM_io_add(m_p), infoM_parse), 0);
			}
			break;
		default:
			return 0;
		}
	}	
	return rv;
}

size_t testM_serial(test* m_p, uint8_t* out)
{
	uint8_t* back_out = out;
	
	check_null(m_p, 0);
	check_null(out, 0);
	out += pbc_write_int32(out, PROTOBUF_C_LABEL_REQUIRED, &m_p->_a, 1);		// write int32 a
	out += pbc_write_int32(out, PROTOBUF_C_LABEL_REQUIRED, &m_p->_b, 2);		// write int32 b
	out += pbc_write_int32(out, PROTOBUF_C_LABEL_REQUIRED, &m_p->_c, 3);		// write int32 c
	out += pbc_write_int32(out, PROTOBUF_C_LABEL_REPEATED, &m_p->_d, 4);		// write repeated int32 d
	out += pbc_write_message(out, PROTOBUF_C_LABEL_REPEATED, &m_p->_io, (message_serial)infoM_serial, 5);
	return out - back_out;
}

void freeM_test(test* m_p)
{
	if(m_p==NULL)
		return;
	freeV_pbc_list( &((m_p)->_d) );
	freeV_pbc_list( &((m_p)->_io) );
	free(m_p);
}